SPDX-FileCopyrightText: 2021 Raban Ohlhoff & Jules Dewez SPDX-FileCopyrightText: 2024 AlICe laboratory https://alicelab.be
SPDX-License-Identifier: GPL-3.0-or-later
Blender 3.1 | Linux | Python 3.10
To execute the script you need to have the two ‘csv’ Files: PARTITION.csv and GROUPES.csv. Change the path under DATA IMPORT/MANIPULATION accordingly. Furthermore you need to have the following Python libraries installed: Pandas, Random, Math, Numpy, Mathutils, Time. Please note that this script is tested for Blender 3.1 and Python 3.10 if any error occurs please try installing blender 3.1. Once the script is executed you can play the animation by clicking on play in the timeline.
import bpy
import pandas
import random
import math
import numpy
from mathutils import Vector
import timepartition_table = pandas.read_csv(
    "/home/sinasta/Documents/MASTER/1sem/AIM/PHASE II/CSV/PARTITION.csv"
)  # import the general csv file (change to new CSV path)
group_table = pandas.read_csv(
    "/home/sinasta/Documents/MASTER/1sem/AIM/PHASE II/CSV/GROUPES.csv"
)  # import the group csv file (change to new CSV path)
t_max = 5  # map values to fit in cube
t_min = -5
partition_table.loc[:, ["HEIGHT", "SIZE", "% OF INFO"]] -= partition_table.loc[
    :, ["HEIGHT", "SIZE", "% OF INFO"]
].min()
partition_table.loc[:, ["HEIGHT", "SIZE", "% OF INFO"]] /= (
    partition_table.loc[:, ["HEIGHT", "SIZE", "% OF INFO"]].max()
    - partition_table.loc[:, ["HEIGHT", "SIZE", "% OF INFO"]].min()
)
partition_table.loc[:, ["HEIGHT", "SIZE", "% OF INFO"]] *= t_max - t_min
partition_table.loc[:, ["HEIGHT", "SIZE", "% OF INFO"]] += t_minstart_time = time.time()
random.seed()
total_group_amount = len(partition_table)
total_amount_of_symbols = len(group_table.columns) - 2
start_frame = bpy.context.scene.frame_start
end_frame = bpy.context.scene.frame_endlist_of_symbols = list(group_table)[2:]  # get list of symbols
list_of_group_relations = partition_table["RELATION"].tolist()def clean_terminal():
    for i in range(20):
        print(" ")def unhide_all():
    bpy.ops.object.select_all(action="DESELECT")
    for obj in bpy.data.objects:
        obj.hide_viewport = False
        obj.hide_render = False
        obj.hide_set(False)
        obj.hide_select = Falsedef clean():
    unhide_all()
    bpy.ops.object.select_all(action="SELECT")  # clean the viewport
    bpy.ops.object.delete(use_global=False)
    bpy.ops.outliner.orphans_purge()
    for c in bpy.context.scene.collection.children:
        bpy.context.scene.collection.children.unlink(c)
    for c in bpy.data.collections:
        if not c.users:
            bpy.data.collections.remove(c)def scene_setup():
    bpy.context.scene.frame_start = 0
    bpy.context.scene.frame_end = get_group_end_time(18) * 30
    bpy.context.scene.render.resolution_y = 2248
    bpy.context.scene.render.resolution_x = 4000
    bpy.context.scene.render.filepath = "/home/sinasta/Documents/MASTER/1sem/AIM/PHASE II/Render/"  # change for render output directorydef map_values(value, old_min, old_max, new_min, new_max):
    old_span = old_max - old_min
    new_span = new_max - new_min
    value_scaled = (value - old_min) / (old_span)
    return new_min + (value_scaled * new_span)def show_on_second():
    bpy.context.object.hide_viewport = True
    bpy.context.object.hide_render = True
    bpy.context.object.keyframe_insert(
        data_path="hide_viewport", frame=bpy.context.scene.frame_current - 1
    )
    bpy.context.object.keyframe_insert(
        data_path="hide_render", frame=bpy.context.scene.frame_current - 1
    )
    bpy.context.object.hide_viewport = False
    bpy.context.object.hide_render = False
    bpy.context.object.keyframe_insert(
        data_path="hide_viewport", frame=bpy.context.scene.frame_current
    )
    bpy.context.object.keyframe_insert(
        data_path="hide_render", frame=bpy.context.scene.frame_current
    )
    bpy.context.object.hide_viewport = True
    bpy.context.object.hide_render = True
    bpy.context.object.keyframe_insert(
        data_path="hide_viewport", frame=bpy.context.scene.frame_current + 30
    )
    bpy.context.object.keyframe_insert(
        data_path="hide_render", frame=bpy.context.scene.frame_current + 30
    )def frame_to_second():
    return int(bpy.context.scene.frame_current / 30)def convert_to_second(frame):
    return int(frame / 30)def get_origin_vector(
    group_number,
):  # get origin vector per group (size, % of info, height)
    three_value_table = partition_table.loc[
        group_number, ["SIZE", "% OF INFO", "HEIGHT"]
    ]
    return three_value_table.values.tolist()def get_origin_vector_list():  # get list of origin vectors per group (size, % of info, height)
    origin_vector_list = []
    for i in range(total_group_amount):
        origin_vector_list.append(get_origin_vector(i))
    return origin_vector_listdef get_group_start_time(group_number):  # get starttime per group
    return int(partition_table.loc[group_number, ["START TIME"]][0])def get_active_groups_per_time(time):  # get active groups per second
    group_numbers = []
    for i in range(total_group_amount):
        if time >= get_group_start_time(i) and time <= get_group_end_time(i):
            group_numbers.append(i)
    if len(group_numbers) == 0:
        group_numbers.append("no group")
    return group_numbersdef get_group_duration(group_number):  # get duration per group in seconds
    return group_table.loc[group_table["GROUP"] == group_number + 1].shape[0] - 1def get_group_end_time(group_number):  # get ending second per group
    return get_group_start_time(group_number) + get_group_duration(group_number)def get_relative_time(group_number, time):  # count relative time per group
    relative_time = 0
    if time >= get_group_start_time(group_number) and time <= get_group_end_time(
        group_number
    ):
        relative_time = time - get_group_start_time(group_number) + 1
    else:
        relative_time = "not active"
    return relative_timedef get_group_height_value(
    group_number, second, symbol
):  # get individual height value per symbol and second
    individual_group_table = group_table.loc[group_table["GROUP"] == group_number + 1]
    individual_values_per_second = individual_group_table.loc[
        individual_group_table["TIME"] == second
    ]
    height_value = int(individual_values_per_second.iloc[:, symbol + 2].tolist()[0])
    return height_valuedef get_group_amount_value(
    group_number, second, symbol
):  # get individual amount value per symbol and second
    individual_group_table = group_table.loc[group_table["GROUP"] == group_number + 1]
    individual_values_per_second = individual_group_table.loc[
        individual_group_table["TIME"] == second
    ]
    amount_value = round(
        abs(individual_values_per_second.iloc[:, symbol + 2].tolist()[0]) % 1 * 10
    )
    return amount_valuedef get_active_values_and_groups_per_time_and_symbol(
    time, symbol
):  # get list of active groups, amount and height values per time
    height_values = []
    amount_values = []
    active_group_list = get_active_groups_per_time(time)
    if active_group_list[0] != "no group":
        for i in range(len(active_group_list)):
            active_group = active_group_list[i]
            relative_time = get_relative_time(active_group, time)
            height_value = get_group_height_value(active_group, relative_time, symbol)
            height_values.append(height_value)
            amount_value = get_group_amount_value(active_group, relative_time, symbol)
            amount_values.append(amount_value)
    else:
        height_values.append("no group"), amount_values.append("no group")
    return active_group_list, height_values, amount_valuesdef get_symbols_per_time(
    time,
):  # get all symbols (even blanks) per time divided by groups
    list_of_symbols_amount = []
    list_of_symbols_height = []
    for i in range(total_amount_of_symbols):
        (
            active_group_list,
            amount_values,
            height_values,
        ) = get_active_values_and_groups_per_time_and_symbol(time, i)
        list_of_symbols_amount.append(amount_values)
        list_of_symbols_height.append(height_values)
    return active_group_list, list_of_symbols_amount, list_of_symbols_heightdef get_frame_cube_coordinates_list():
    frame = bpy.data.objects["Frame"]
    coordinates = [(frame.matrix_world @ points.co) for points in frame.data.vertices]
    plein_coordinates = [points.to_tuple() for points in coordinates]
    coordinates_list = []
    for i in range(len(plein_coordinates)):
        coordinates_list.append(list(plein_coordinates[i]))
    return coordinates_listdef new_collection(name):    def find_layer_collection_recursive(find, col):
        for c in col.children:
            if c.collection == find:
                return c
        return None
    my_collection = bpy.data.collections.new(name)
    bpy.context.scene.collection.children.link(my_collection)
    found = find_layer_collection_recursive(
        my_collection, bpy.context.view_layer.layer_collection
    )
    if found:
        bpy.context.view_layer.active_layer_collection = founddef generate_frame_cube():
    bpy.ops.object.select_all(action="DESELECT")
    bpy.ops.mesh.primitive_cube_add(
        size=1, rotation=(0, 0, 0), scale=(10, 10, 10)
    )  # create frame cube
    bpy.context.object.name = "Frame"
    bpy.context.object.display_type = "WIRE"
    bpy.data.objects["Frame"].hide_render = Truedef generate_spheres_at_origins():
    bpy.ops.object.select_all(action="DESELECT")
    for i in range(total_group_amount):
        vector_list = get_origin_vector(i)
        origin_vector = vector_list[:-1] + [vector_list[2]]
        bpy.ops.mesh.primitive_ico_sphere_add(
            subdivisions=2,
            radius=(list_of_group_relations[i] / 8),
            location=(origin_vector),
            scale=(1, 1, 1),
        )
        bpy.context.object.name = "origin_group_" + str(i)
        bpy.ops.object.modifier_add(type="SUBSURF")
        bpy.context.object.modifiers["Subdivision"].levels = 0
        bpy.context.object.modifiers["Subdivision"].render_levels = 0
        bpy.ops.object.modifier_add(type="WIREFRAME")
        bpy.context.object.modifiers["Wireframe"].thickness = 0.08
        bpy.context.object.modifiers["Wireframe"].use_replace = False
        bpy.context.object.modifiers["Wireframe"].use_even_offset = False
        bpy.context.object.hide_viewport = True
        bpy.context.object.hide_render = True
        bpy.context.object.keyframe_insert(data_path="hide_viewport", frame=0)
        bpy.context.object.keyframe_insert(data_path="hide_render", frame=0)
        bpy.context.object.hide_viewport = False
        bpy.context.object.hide_render = False
        bpy.context.object.scale = (1, 1, 1)
        bpy.context.object.keyframe_insert(
            data_path="hide_viewport", frame=get_group_start_time(i) * 30
        )
        bpy.context.object.keyframe_insert(
            data_path="hide_render", frame=get_group_start_time(i) * 30
        )
        bpy.context.object.keyframe_insert(
            data_path="scale", frame=get_group_start_time(i) * 30
        )
        bpy.context.object.hide_viewport = True
        bpy.context.object.hide_render = True
        duration = 1 + get_group_duration(i) / 40
        bpy.context.object.scale = (duration, duration, duration)
        bpy.context.object.keyframe_insert(
            data_path="hide_viewport", frame=get_group_end_time(i) * 30
        )
        bpy.context.object.keyframe_insert(
            data_path="hide_render", frame=get_group_end_time(i) * 30
        )
        bpy.context.object.keyframe_insert(
            data_path="scale", frame=get_group_end_time(i) * 30
        )def animate_origins():
    for i in range(int(bpy.context.scene.frame_end / 30)):
        level = transform_treble_key_symbol(i)
        transparency = transform_bass_key_symbol(i)
        print(
            "  ", round(((i + 1) / int(bpy.context.scene.frame_end / 30)) * 100, 1), "%"
        )
        if level == 0:
            for j in range(19):
                bpy.data.objects["origin_group_" + str(j)].modifiers[
                    "Subdivision"
                ].levels = 1
                bpy.data.objects["origin_group_" + str(j)].modifiers[
                    "Subdivision"
                ].render_levels = 1
                bpy.data.objects["origin_group_" + str(j)].modifiers[
                    "Subdivision"
                ].keyframe_insert(data_path="levels", frame=i * 30)
                bpy.data.objects["origin_group_" + str(j)].modifiers[
                    "Subdivision"
                ].keyframe_insert(data_path="render_levels", frame=i * 30)
        if level > 0:
            for j in range(19):
                bpy.data.objects["origin_group_" + str(j)].modifiers[
                    "Subdivision"
                ].levels = 0
                bpy.data.objects["origin_group_" + str(j)].modifiers[
                    "Subdivision"
                ].render_levels = 0
                bpy.data.objects["origin_group_" + str(j)].modifiers[
                    "Subdivision"
                ].keyframe_insert(data_path="levels", frame=i * 30)
                bpy.data.objects["origin_group_" + str(j)].modifiers[
                    "Subdivision"
                ].keyframe_insert(data_path="render_levels", frame=i * 30)
        if transparency == 0:
            for o in range(19):
                bpy.data.objects["origin_group_" + str(o)].modifiers[
                    "Wireframe"
                ].use_replace = False
                bpy.data.objects["origin_group_" + str(o)].modifiers[
                    "Wireframe"
                ].keyframe_insert(data_path="use_replace", frame=i * 30)
        if transparency > 0:
            for p in range(19):
                bpy.data.objects["origin_group_" + str(p)].modifiers[
                    "Wireframe"
                ].use_replace = True
                bpy.data.objects["origin_group_" + str(p)].modifiers[
                    "Wireframe"
                ].keyframe_insert(data_path="use_replace", frame=i * 30)def generate_group_wire():
    bpy.ops.object.select_all(action="DESELECT")
    origin_list = get_origin_vector_list()
    frame_list = get_frame_cube_coordinates_list()
    origin_list.extend(frame_list)
    group_wire = bpy.data.curves.new("group_wire", "CURVE")  # make a new curve
    group_wire.dimensions = "3D"
    group_wire.bevel_depth = 0.16
    group_wire.bevel_resolution = 10
    group_wire_spline = group_wire.splines.new(
        type="NURBS"
    )  # make a new spline in that curve
    group_wire_spline.points.add(len(origin_list) - 1)  # a spline point for each point
    group_wire.splines[0].use_cyclic_u = True
    group_wire.splines[0].order_u = 2
    group_wire.splines[0].resolution_u = 45
    for p, new_point in zip(
        group_wire_spline.points, origin_list
    ):  # assign the point coordinates to the spline points
        p.co = new_point + [1.0]
    group_wire_object = bpy.data.objects.new(
        "group_wire", group_wire
    )  # make a new object with the curve
    bpy.context.scene.collection.objects.link(group_wire_object)
    group_wire = bpy.context.scene.objects["group_wire"]
    bpy.ops.object.select_all(action="DESELECT")
    bpy.context.view_layer.objects.active = group_wire
    group_wire.select_set(True)
    bpy.ops.object.modifier_add(type="BUILD")
    bpy.context.object.modifiers["Build"].frame_duration = bpy.context.scene.frame_enddef animate_group_wire():
    for i in range(int(bpy.context.scene.frame_end / 30)):
        marcato = transform_marcato_symbol(i)
        diminuendo = transform_diminuendo_symbol(i)
        print(
            "  ", round(((i + 1) / int(bpy.context.scene.frame_end / 30)) * 100, 1), "%"
        )
        if marcato:
            present_size = bpy.data.curves["group_wire"].bevel_depth
            bpy.data.curves["group_wire"].bevel_depth = present_size + 0.04
            bpy.data.curves["group_wire"].keyframe_insert(
                data_path="bevel_depth", frame=i * 30
            )
            bpy.data.curves["group_wire"].bevel_depth = present_size
        elif diminuendo:
            bpy.data.curves["group_wire"].bevel_depth = (
                bpy.data.curves["group_wire"].bevel_depth - 0.002
            )
            bpy.data.curves["group_wire"].keyframe_insert(
                data_path="bevel_depth", frame=i * 30
            )
        else:
            bpy.data.curves["group_wire"].keyframe_insert(
                data_path="bevel_depth", frame=i * 30
            )def generate_trimetric_cam():
    cam_data = bpy.data.cameras.new("trimetric_camera")
    cam = bpy.data.objects.new("trimetric_camera", cam_data)
    bpy.data.collections[
        bpy.context.view_layer.active_layer_collection.collection.name
    ].objects.link(cam)
    bpy.context.scene.camera = cam
    cam.data.type = "ORTHO"
    cam.data.ortho_scale = 31.7
    cam.location = Vector((8, -13, 6.5))
    cam.rotation_euler = (math.radians(67), 0.0, math.radians(34))def animate_camera():
    bpy.ops.object.select_all(action="DESELECT")
    bpy.ops.object.empty_add(
        type="PLAIN_AXES", align="WORLD", location=(0, 0, 0), scale=(1, 1, 1)
    )
    bpy.data.objects["Empty"].name = "Camera_rotation"
    bpy.data.objects["Camera_rotation"].keyframe_insert(
        data_path="rotation_euler", frame=0
    )
    bpy.data.objects["Camera_rotation"].rotation_euler[2] = math.radians(180)
    bpy.data.objects["Camera_rotation"].keyframe_insert(
        data_path="rotation_euler", frame=get_group_end_time(18) * 30
    )
    bpy.data.objects["trimetric_camera"].parent = bpy.data.objects["Camera_rotation"]def generate_horizontal_symbol():
    amount = 4
    vertex_weight = 1
    x1, x2, x3, x4, y1, y2, y3, y4 = -15, -5, 5, 15, 15, 5, -5, -15
    low_left = 0
    high_left = 0
    low_right = 0
    high_right = 0
    points = [
        Vector((x1, y1, random.uniform(low_left, high_left), vertex_weight)),
        Vector((x1, y2, random.uniform(low_left, high_left), vertex_weight)),
        Vector((x1, y3, random.uniform(low_left, high_left), vertex_weight)),
        Vector((x1, y4, random.uniform(low_left, high_left), vertex_weight)),
        Vector((x2, y1, random.uniform(low_left, high_left), vertex_weight)),
        Vector((x2, y2, random.uniform(low_left, high_left), vertex_weight)),
        Vector((x2, y3, random.uniform(low_left, high_left), vertex_weight)),
        Vector((x2, y4, random.uniform(low_left, high_left), vertex_weight)),
        Vector((x3, y1, random.uniform(low_right, high_right), vertex_weight)),
        Vector((x3, y2, random.uniform(low_right, high_right), vertex_weight)),
        Vector((x3, y3, random.uniform(low_right, high_right), vertex_weight)),
        Vector((x3, y4, random.uniform(low_right, high_right), vertex_weight)),
        Vector((x4, y1, random.uniform(low_right, high_right), vertex_weight)),
        Vector((x4, y2, random.uniform(low_right, high_right), vertex_weight)),
        Vector((x4, y3, random.uniform(low_right, high_right), vertex_weight)),
        Vector((x4, y4, random.uniform(low_right, high_right), vertex_weight)),
    ]
    for y in range(amount):
        surface_data = bpy.data.curves.new("horizontal_" + str(y), "SURFACE")
        for f in range(0, len(points), 4):
            spline = surface_data.splines.new(type="NURBS")
            spline.points.add(3)
            for p, new_co in zip(spline.points, points[f : f + 4]):
                p.co = new_co
        horizontal_surface = bpy.data.objects.new("horizontal_" + str(y), surface_data)
        bpy.data.collections[
            bpy.context.view_layer.active_layer_collection.collection.name
        ].objects.link(horizontal_surface)
        splines = horizontal_surface.data.splines
        for s in splines:
            for p in s.points:
                p.select = True
        bpy.context.view_layer.objects.active = horizontal_surface
        bpy.ops.object.mode_set(mode="EDIT")
        bpy.ops.curve.make_segment()
        bpy.ops.object.mode_set(mode="OBJECT")
        horizontal = bpy.context.scene.objects["horizontal_" + str(y)]
        bpy.ops.object.select_all(action="DESELECT")
        bpy.context.view_layer.objects.active = horizontal
        horizontal.select_set(True)
        bpy.context.object.data.resolution_v = 10
        bpy.context.object.data.resolution_u = 10
        bpy.ops.object.mode_set(mode="EDIT")
        for i in range(len(bpy.data.curves["horizontal_" + str(y)].splines[0].points)):
            bpy.ops.curve.select_all(action="DESELECT")
            bpy.data.curves["horizontal_" + str(y)].splines[0].points[i].select = True
            bpy.ops.object.hook_add_newob()
            bpy.data.objects["Empty"].name = "empty_" + str(y) + "_" + str(i)
        bpy.ops.object.mode_set(mode="OBJECT")
        bpy.ops.object.empty_add(
            type="PLAIN_AXES", align="WORLD", location=(0, 0, 0), scale=(1, 1, 1)
        )
        position = bpy.context.selected_objects[0]
        position.name = "position_" + str(y)
        bpy.ops.object.select_all(action="DESELECT")
        for o in range(16):
            bpy.data.objects["empty_" + str(y) + "_" + str(o)].select_set(True)
        bpy.data.objects["position_" + str(y)].select_set(True)
        bpy.ops.object.parent_set(type="OBJECT")
        bpy.ops.object.select_all(action="DESELECT")
        bpy.context.view_layer.objects.active = bpy.data.objects["horizontal_" + str(y)]
        bpy.ops.object.modifier_add(type="SOLIDIFY")
        bpy.context.object.modifiers["Solidify"].thickness = 0.15
        bpy.ops.object.modifier_add(type="ARRAY")
        bpy.context.object.modifiers["Array"].count = 1
        bpy.context.object.modifiers["Array"].relative_offset_displace[0] = 0def animate_horizontals():
    symbol = 0
    for i in range(int(bpy.context.scene.frame_end / 30)):
        list_of_symbols = get_symbols_per_time(i)
        print(
            "  ", round(((i + 1) / int(bpy.context.scene.frame_end / 30)) * 100, 1), "%"
        )
        if (
            list_of_symbols[1][0][0] != "no group"
            and sum(list_of_symbols[1][symbol]) != 0
        ):
            slur_down = transform_slur_down_symbol(i)
            slur_up = transform_slur_up_symbol(i)
            slur = (slur_up - slur_down) / 1.8
            legato = transform_legato_symbol(i) * 2
            turn = 0
            turns = []
            for y, element in enumerate(list_of_symbols[1][symbol]):
                if element != 0:
                    height = map_values(element, -5, 13, -4, 4)
                    amount = list_of_symbols[2][symbol][y]
                    bpy.data.objects["position_" + str(turn)].location[2] = height
                    bpy.data.objects["position_" + str(turn)].keyframe_insert(
                        data_path="location", frame=i * 30
                    )
                    bpy.data.objects["horizontal_" + str(turn)].modifiers[
                        "Array"
                    ].count = amount
                    bpy.data.objects["horizontal_" + str(turn)].modifiers[
                        "Array"
                    ].use_relative_offset = False
                    bpy.data.objects["horizontal_" + str(turn)].modifiers[
                        "Array"
                    ].use_constant_offset = True
                    bpy.data.objects["horizontal_" + str(turn)].modifiers[
                        "Array"
                    ].constant_offset_displace[0] = 0
                    if amount == 1:
                        bpy.data.objects["horizontal_" + str(turn)].modifiers[
                            "Array"
                        ].constant_offset_displace[2] = 0
                    elif amount == 2:
                        bpy.data.objects["horizontal_" + str(turn)].modifiers[
                            "Array"
                        ].constant_offset_displace[2] = -0.8
                    elif amount == 3:
                        bpy.data.objects["horizontal_" + str(turn)].modifiers[
                            "Array"
                        ].constant_offset_displace[2] = -0.5
                    bpy.data.objects["horizontal_" + str(turn)].modifiers[
                        "Array"
                    ].keyframe_insert(data_path="count", frame=i * 30)
                    bpy.data.objects["horizontal_" + str(turn)].modifiers[
                        "Array"
                    ].keyframe_insert(
                        data_path="constant_offset_displace", frame=i * 30
                    )
                    bpy.data.objects["horizontal_" + str(turn)].hide_viewport = False
                    bpy.data.objects["horizontal_" + str(turn)].hide_render = False
                    bpy.data.objects["horizontal_" + str(turn)].keyframe_insert(
                        data_path="hide_viewport", frame=i * 30
                    )
                    for z in range(16):
                        for z in [0, 1, 2, 3, 4, 7]:
                            base_location = bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(z)
                            ].location[2]
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(z)
                            ].location[2] = (
                                random.uniform(-1 - legato, 1 - legato) - slur
                            )
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(z)
                            ].keyframe_insert(data_path="location", frame=i * 30)
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(z)
                            ].location[2] = base_location
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(z)
                            ].keyframe_insert(data_path="location", frame=i * 30 + 30)
                        for p in [5, 6]:
                            base_location = bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(p)
                            ].location[2]
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(p)
                            ].location[2] = (
                                random.uniform(-1 + legato, 1 + legato) - slur
                            )
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(p)
                            ].keyframe_insert(data_path="location", frame=i * 30)
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(p)
                            ].location[2] = base_location
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(p)
                            ].keyframe_insert(data_path="location", frame=i * 30 + 30)
                        for o in [8, 11, 12, 13, 14, 15]:
                            base_location = bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(o)
                            ].location[2]
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(o)
                            ].location[2] = (
                                random.uniform(-1 - legato, 1 - legato) + slur
                            )
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(o)
                            ].keyframe_insert(data_path="location", frame=i * 30)
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(o)
                            ].location[2] = base_location
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(o)
                            ].keyframe_insert(data_path="location", frame=i * 30 + 30)
                        for b in [9, 10]:
                            base_location = bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(b)
                            ].location[2]
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(b)
                            ].location[2] = (
                                random.uniform(-1 + legato, 1 + legato) + slur
                            )
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(b)
                            ].keyframe_insert(data_path="location", frame=i * 30)
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(b)
                            ].location[2] = base_location
                            bpy.data.objects[
                                "empty_" + str(turn) + "_" + str(b)
                            ].keyframe_insert(data_path="location", frame=i * 30 + 30)
                    turns.append(turn)
                    turn = turn + 1
            for v in range(4):
                if v not in turns:
                    bpy.data.objects["horizontal_" + str(v)].hide_viewport = True
                    bpy.data.objects["horizontal_" + str(v)].hide_render = True
                    bpy.data.objects["horizontal_" + str(v)].keyframe_insert(
                        data_path="hide_viewport", frame=i * 30
                    )
        else:
            for q in range(4):
                bpy.data.objects["horizontal_" + str(q)].hide_viewport = True
                bpy.data.objects["horizontal_" + str(q)].hide_render = True
                bpy.data.objects["horizontal_" + str(q)].keyframe_insert(
                    data_path="hide_viewport", frame=i * 30
                )def generate_vertical_symbol():
    symbol = 1
    list_of_symbols = get_symbols_per_time(frame_to_second())
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[1][symbol]):
            if element != 0:
                height = element
                amount = list_of_symbols[2][symbol][i]
                rotation_degree = map_values(height, -10, 8, -20, 20)
                thickness = amount / 3
                bpy.ops.mesh.primitive_cube_add(
                    size=2,
                    enter_editmode=False,
                    align="WORLD",
                    location=(random.uniform(-4, 4), random.uniform(-4, 4), 0),
                    rotation=(
                        random.uniform(-1, 1) * rotation_degree * math.pi / 180,
                        random.uniform(-1, 1) * rotation_degree * math.pi / 180,
                        random.uniform(-1, 1) * rotation_degree * math.pi / 180,
                    ),
                    scale=(thickness, thickness, 7),
                )
                bpy.context.object.name = "vertical"
                show_on_second()def generate_note_symbol(negate, scale_up, scale_down, multiply_2, multiply_3, bevel):
    symbol = 4
    second = frame_to_second()
    list_of_symbols = get_symbols_per_time(second)
    if negate:
        scale_up = 1
        scale_down = 1
    if multiply_2 or multiply_3:
        if multiply_3 == False:
            factor = 2
        elif multiply_2 == False:
            factor = 3
        else:
            factor = 4
    else:
        factor = 1
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i in range(factor):
            for j, element in enumerate(list_of_symbols[1][symbol]):
                if element != 0:
                    height_unmapped = element
                    amount = list_of_symbols[2][symbol][j]
                    height = map_values(height_unmapped, -11, 15, -4, 4)
                    for k in range(amount * 2):
                        bpy.ops.mesh.primitive_cube_add(
                            size=1,
                            enter_editmode=False,
                            align="WORLD",
                            location=(
                                random.uniform(-4, 4),
                                random.uniform(-4, 4),
                                height + random.uniform(-1, 1),
                            ),
                            rotation=(
                                math.radians(random.uniform(-45, 45)),
                                math.radians(random.uniform(-45, 45)),
                                math.radians(random.uniform(-45, 45)),
                            ),
                            scale=(
                                random.uniform(1, 2.5) * scale_up * scale_down,
                                random.uniform(1, 2.5) * scale_up * scale_down,
                                random.uniform(1, 2.5) * scale_up * scale_down,
                            ),
                        )
                        bpy.context.object.name = (
                            "note_"
                            + str(second)
                            + "_"
                            + str(i)
                            + "_"
                            + str(j)
                            + "_"
                            + str(k)
                        )
                        if bevel:
                            bpy.ops.object.modifier_add(type="BEVEL")
                            bpy.context.object.modifiers["Bevel"].offset_type = (
                                "PERCENT"
                            )
                            bpy.context.object.modifiers["Bevel"].width_pct = 40
                        show_on_second()def generate_number_one_symbol():
    symbol = 14
    list_of_symbols = get_symbols_per_time(frame_to_second())
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[1][symbol]):
            if element != 0:
                height = element
                amount = list_of_symbols[2][symbol][i]
                rotation_degree = map_values(height, -6, 11, -20, 20)
                thickness = amount / 3
                bpy.ops.mesh.primitive_cube_add(
                    size=2,
                    enter_editmode=False,
                    align="WORLD",
                    location=(0, random.uniform(-4, 4), random.uniform(-4, 4)),
                    rotation=(
                        random.uniform(-1, 1) * rotation_degree * math.pi / 180,
                        random.uniform(-1, 1) * rotation_degree * math.pi / 180,
                        random.uniform(-1, 1) * rotation_degree * math.pi / 180,
                    ),
                    scale=(7, thickness, thickness),
                )
                bpy.context.object.name = "number_one"
                show_on_second()def generate_number_two_symbol():
    symbol = 15
    list_of_symbols = get_symbols_per_time(frame_to_second())
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[1][symbol]):
            if element != 0:
                height = element
                amount = list_of_symbols[2][symbol][i]
                rotation_degree = map_values(height, -2, -1, -20, 20)
                thickness = amount / 3
                for i in range(2):
                    rotation_degree = height
                    thickness = amount / 2
                    bpy.ops.mesh.primitive_cube_add(
                        size=2,
                        enter_editmode=False,
                        align="WORLD",
                        location=(0, random.uniform(-4, 4), random.uniform(-4, 4)),
                        rotation=(
                            random.uniform(-1, 1) * rotation_degree * math.pi / 180,
                            random.uniform(-1, 1) * rotation_degree * math.pi / 180,
                            random.uniform(-1, 1) * rotation_degree * math.pi / 180,
                        ),
                        scale=(7, thickness, thickness),
                    )
                    bpy.context.object.name = "number_two"
                    show_on_second()def generate_circle_symbol():
    symbol = 2
    list_of_symbols = get_symbols_per_time(frame_to_second())
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[1][symbol]):
            if element != 0:
                height_unmapped = element
                amount = list_of_symbols[2][symbol][i]
                height = map_values(height_unmapped, -10, 21, -4.5, 4.5)
                bpy.ops.mesh.primitive_cylinder_add(
                    vertices=60,
                    end_fill_type="NOTHING",
                    radius=(2.5 + random.uniform(0, 4)),
                    depth=random.uniform(0.5, 1),
                    enter_editmode=False,
                    align="WORLD",
                    location=(random.uniform(-4, 4), random.uniform(-4, 4), height),
                    rotation=(
                        math.radians(random.uniform(-45, 45)),
                        math.radians(random.uniform(-45, 45)),
                        math.radians(random.uniform(-45, 45)),
                    ),
                    scale=(1, 1, 1),
                )
                bpy.ops.object.modifier_add(type="SIMPLE_DEFORM")
                bpy.context.object.modifiers["SimpleDeform"].deform_axis = "Z"
                bpy.context.object.modifiers["SimpleDeform"].angle = math.radians(
                    50 + 30 * amount
                )
                bpy.ops.object.modifier_add(type="WIREFRAME")
                bpy.context.object.modifiers["Wireframe"].thickness = 0.1
                bpy.context.object.modifiers["Wireframe"].use_boundary = True
                bpy.context.object.modifiers["Wireframe"].use_even_offset = True
                bpy.context.object.name = (
                    "circle_" + str(frame_to_second()) + "_" + str(i)
                )
                bpy.data.objects[
                    "circle_" + str(frame_to_second()) + "_" + str(i)
                ].modifiers["SimpleDeform"].keyframe_insert(
                    data_path="angle", frame=frame_to_second() * 30 + 30
                )
                bpy.data.objects[
                    "circle_" + str(frame_to_second()) + "_" + str(i)
                ].keyframe_insert(data_path="scale", frame=frame_to_second() * 30 + 20)
                bpy.data.objects[
                    "circle_" + str(frame_to_second()) + "_" + str(i)
                ].scale[0] = 0.5
                bpy.data.objects[
                    "circle_" + str(frame_to_second()) + "_" + str(i)
                ].scale[1] = 0.5
                bpy.data.objects[
                    "circle_" + str(frame_to_second()) + "_" + str(i)
                ].keyframe_insert(data_path="scale", frame=frame_to_second() * 30)
                bpy.data.objects[
                    "circle_" + str(frame_to_second()) + "_" + str(i)
                ].modifiers["SimpleDeform"].angle = 0
                bpy.data.objects[
                    "circle_" + str(frame_to_second()) + "_" + str(i)
                ].modifiers["SimpleDeform"].keyframe_insert(
                    data_path="angle", frame=frame_to_second() * 30
                )
                show_on_second()def transform_legato_symbol(second):
    symbol = 3
    list_of_symbols = get_symbols_per_time(second)
    amount_list = []
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[2][symbol]):
            if element != 0:
                amount = element
                amount_list.append(amount)
    else:
        amount_list.append(0)
    return sum(amount_list)def transform_slur_up_symbol(second):
    symbol = 5
    list_of_symbols = get_symbols_per_time(second)
    amount_list = []
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[2][symbol]):
            if element != 0:
                amount = element
                amount_list.append(amount)
    else:
        amount_list.append(0)
    return sum(amount_list)def transform_slur_down_symbol(second):
    symbol = 6
    list_of_symbols = get_symbols_per_time(second)
    amount_list = []
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[2][symbol]):
            if element != 0:
                amount = element
                amount_list.append(amount)
    else:
        amount_list.append(0)
    return sum(amount_list)def transform_bass_key_symbol(second):
    symbol = 7
    list_of_symbols = get_symbols_per_time(second)
    height_list = []
    amount_list = []
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[2][symbol]):
            if element != 0:
                amount_list.append(element)
    else:
        amount_list.append(0)
    return sum(amount_list)def transform_treble_key_symbol(second):
    symbol = 8
    list_of_symbols = get_symbols_per_time(second)
    height_list = []
    amount_list = []
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[2][symbol]):
            if element != 0:
                amount_list.append(element)
    else:
        amount_list.append(0)
    return sum(amount_list)def transform_sharp_symbol():
    symbol = 9
    list_of_symbols = get_symbols_per_time(frame_to_second())
    result_list = []
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[1][symbol]):
            if element != 0:
                height = map_values(element, -5, 7, 1.1, 2.3)
                amount = list_of_symbols[2][symbol][i]
                result_list.append(height)
    else:
        result_list.append(1)
    return sum(result_list) / len(result_list)def transform_flat_symbol():
    symbol = 10
    list_of_symbols = get_symbols_per_time(frame_to_second())
    result_list = []
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        for i, element in enumerate(list_of_symbols[1][symbol]):
            if element != 0:
                height = map_values(element, -10, 8, 1, 5)
                amount = list_of_symbols[2][symbol][i]
                result_list.append((1 - height / 10) / (amount / 10 + 1))
    else:
        result_list.append(1)
    return sum(result_list) / len(result_list)def transform_marcato_symbol(second):
    symbol = 11
    list_of_symbols = get_symbols_per_time(second)
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        result = True
    else:
        result = False
    return resultdef transform_natural_symbol():
    symbol = 12
    list_of_symbols = get_symbols_per_time(frame_to_second())
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        result = True
    else:
        result = False
    return resultdef transform_diminuendo_symbol(second):
    symbol = 13
    list_of_symbols = get_symbols_per_time(second)
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        result = True
    else:
        result = False
    return resultdef transform_staccato_symbol():
    symbol = 16
    list_of_symbols = get_symbols_per_time(frame_to_second())
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        result = True
    else:
        result = False
    return resultdef transform_sullarco_symbol():
    symbol = 17
    list_of_symbols = get_symbols_per_time(frame_to_second())
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        result = True
    else:
        result = False
    return resultdef transform_upper_mordent_symbol():
    symbol = 18
    list_of_symbols = get_symbols_per_time(frame_to_second())
    if list_of_symbols[1][0][0] != "no group" and sum(list_of_symbols[1][symbol]) != 0:
        result = True
    else:
        result = False
    return resultclean_terminal()
print("cleaning up ...", end=" ")
clean()
print("preparing the scene ...")
scene_setup()
print("  done")
print("starting generation")
print("")
print("generating Camera ...")
new_collection("Cameras")
generate_trimetric_cam()
animate_camera()
print("  done")
print("generating Cube ...")
new_collection("Frame")
generate_frame_cube()
print("  done")
print("generating Wire ...")
generate_group_wire()
print(" animating Wire ...")
animate_group_wire()
print("  done")
print("generating Origins ...")
new_collection("Origins")
generate_spheres_at_origins()
print(" animating Origins ...")
animate_origins()
print("  done")
print("generating Horizontals ...")
new_collection("Horizontals")
generate_horizontal_symbol()
print(" animating Horizontals ...")
animate_horizontals()
print("  done")
print("")
end = get_group_end_time(18)
for i in range(end):
    bpy.context.scene.frame_set(i * 30)
    print(
        "generating Collection for Second: " + str(i),
        " / " + str(end),
    )
    print("")
    new_collection("Second_" + str(i))
    print("   generating Verticals for Second: " + str(i), "...")
    generate_vertical_symbol()
    print("     done")
    print("   generating Notes for Second: " + str(i), "...")
    generate_note_symbol(
        transform_natural_symbol(),
        transform_sharp_symbol(),
        transform_flat_symbol(),
        transform_sullarco_symbol(),
        transform_upper_mordent_symbol(),
        transform_staccato_symbol(),
    )
    print("     done")
    print("   generating Number One for Second: " + str(i), "...")
    generate_number_one_symbol()
    print("     done")
    print("   generating Number Two for Second: " + str(i), "...")
    generate_number_two_symbol()
    print("     done")
    print("   generating Circles for Second: " + str(i), "...")
    generate_circle_symbol()
    print("     done")
    print("")
print("")
print("execution successfull")
print("execution took: ", round((time.time() - start_time) / 60.0, 2), " minutes")